// AST->code
const generate = require('@babel/generator').default
// code快照
const { codeFrameColumns } = require('@babel/code-frame');
const log4js = require("log4js");
// 监控插件比较灵活，如果项目中有需求需要监控指定页面接口，可以借助此插件进行处理 
// 主要解决全局监听，并捕捉到无关错误信息并上报等痛点问题，并解决外部引入SDK的无痕埋点难自定义的情况
// 
module.exports = ({ types: t }, option, dirname) => {
    return {
        //  使用babel 的设计模式
        visitor: {
            // Identifier类型节点
            // 开发模式将DEBUG转化为字符串   
            CallExpression(path) {
                // 生成code快照
                // 检查callee中是否符合“console”这种模式
                // 進入之前將函數引入,首先在之前加入標記，在下一輪退出的時候 進行函數載入
                // 在这里生成日志 告诉我们的用户 说我帮你改了 ，并告诉开发者改的是那块位置
                let cname = Reflect.get(option, 'funcname') ?? false;
                const calleePath = path.get("callee");  
                if (calleePath.node.name == 'printTips') { 
                    let file = dirname; 
                        const location = { start: { line: 1, column: 5 } };
                        const result = codeFrameColumns(generate(path.node, {}).code, location, {
                            /* options */
                        });
                        // 时间
                        let data = new Date;
                        let time = `${data.getFullYear()}年${data.getMonth() + 1}月${data.getDate()}日`
                        // 配置
                        log4js.configure({
                            appenders: {
                                fileout: { type: "file", filename: `logs/${time}.log` },
                                datafileout: {
                                    type: "dateFile",
                                    filename: "datafileout.log",
                                    pattern: ".yyyy-MM-dd-hh-mm-ss-SSS"
                                },
                                consoleout: { type: "console" },
                            },
                            categories: {
                                default: { appenders: ["fileout", "consoleout"], level: "debug" },
                                anything: { appenders: ["consoleout"], level: "debug" }
                            }
                        });
                        let logger = log4js.getLogger();
                        // 编译日志

                        let log = `编译文件：${file}\n===============================\n${result}\n =============================== \n编译日期：${time}`;
                        // 输出到日志
                        logger.debug(log);
                   // 转化阶段
                   
                   if (/^[a-zA-Z]{5,}$/g.test(cname)) {
                  
                    let genfn = cname + '(%)';
                    // 用户可以在前台随意传入任意参数,这样放弃了全局监听的效果 
                    // 比如埋点点击监控可以出入printTips('click',uuid) 网络请求可以写成 printTips('http',res) ....
                    // 
                    const getargs = (args)=>{
                        let argus = '';
                        // const filters = 
                        args.forEach((item, index) => {
                            let fnname = (item.value ?? item.name);
                            let type = item.type;
                            if (type == 'CallExpression') { 
                                // 第一种情况函数返回值情况--如果函数中还存在参数直接递归处理
                                let callfn = (item.callee.name+'('+ getargs(item.arguments) +')');
                                argus += index == 0 ? callfn : (',' + callfn);
                            } else if (type == 'StringLiteral') {
                                // 第二种情况是函数情况
                                argus += index == 0 ? `"${fnname}"` : (',' + `"${fnname}"`);
                            } else if (type == 'Identifier') {
                                // 第三种情况是普通变量情况
                                argus += index == 0 ? fnname : (',' + fnname);
                            }
                        })
                        return argus;
                    }
                    genfn = genfn.replace('%', getargs(path.node.arguments));
                    // 直接替換 
                    path.replaceWithSourceString(`
                  ${cname} && ${genfn}
                  `);
                } else {
                    path.remove();
                 }
                }
              
                 
            }
         
            

        }

    }
}